TS中的类
// 类的可选参数
class Info {
public name: string
public age?: number
public readonly hobby: number[]
// 申明再constructorconstructor 参数传递过来自动赋值 this.sex = sex
constructor(name: string, age?: number, public sex?: string) {
this.name = name
this.age = age
}
}
// 抽象类只提供方法的定义 继承的类需要去实现对应的定义
abstract class People {
public abstract age: number
constructor(public name: string) { }
abstract getName(): string
abstract get insideAge() :string
abstract set insideAge(value:string)
}
class Man extends People {
public age: number
public insideAge:string
public getName(): string {
return '123'
}
}
// 接口检测的 是使用该接口定义的类的实例 根据实例上属性来判断
interface footInterface {
name:string
}
class Foot implements footInterface {
public name : string
}
// 接口可以继承类
class A {
public name: string
protected hobby:Array<string>
private age:number
}
interface I extends A { }
// 直接实现接口会有问题,如果全是public就不会,如果存在保护 私有的类型 就需要先继承再实现
class B extends A implements I {
public name: string
protected hobby: Array<string>
}
// 接口继承类,如果全是public定义的属性,这里就不会报错,但是存在private protected定义的就会有问题
var n: I = {
name: 'ccc',
age: 123,
hobby:['1']
}
// 久久不能理解的一个写法 实例的类型就是这个类
function createObj<T>(obj: new () => T): T {
return new obj() // 类型创建的实例 类型也就是这个类
}
class C {
public name:string
}
const c : C = createObj(C)
高级类型
// 类型断言 ! 表示不为 null
function getString(num: number | null): string {
function test(prefix:string) {
return prefix + num!.toFixed().toString()
}
num = num || 0.1
return test('hello')
}
// never 配合 switch的使用
// 可以检测当前的判断条件是否使用完,并且传入未知类型的时候抛错
function assertNever(err: never): never {
throw new Error('type error' + err)
}
type circle = {
type: 'circle'
radius: number
}
type rance = {
type: 'rance'
width: number,
height: number
}
type area = circle | rance
function computeAreaArea(area: area) {
switch (area.type) {
case 'circle' :
return area.radius ** 2 * Math.PI
case 'rance':
return area.height * area.width
default :
return assertNever(area)
}
}
// 将一个对象的值转换为get set的形式
type proxy<T> = {
get(): T,
set(v): void
}
type proxify<T> = {
[P in keyof T]: proxy<T[P]>
}
function transform<T>(obj: T): proxify<T> {
let result = {} as proxify<T>
for (var key in obj) {
result[key] = {
get: () => {
return obj[key]
},
set: (value) => {
result[key] = value
}
}
}
return result
}
function unTransform<T>(obj: proxify<T>): T {
let result = {} as T
for (var key in obj) {
result[key] = obj[key].get()
}
return result
}
// 快速增加移除特定限制 可选 只读
// -readonly 移除readonly -? 移除可选
type Remove<T> = {
-readonly [P in keyof T]-?: T[P]
}
// 动态数据类型 根据三目运算来动态决定类型
type TypeName<T> = T extends string ? string :
T extends number ? number :
T extends () => void ? () => void : object
let dynamaticType1: TypeName<string> // string
let dynamaticType2: TypeName<number> // number
let dynamaticType3: TypeName<(() => void) | number> // number | ()=>void
// keyof 会排除类型为 null undefined never
// 理解下面这个写法 [1]将T中的类型先修改了 [2]再使用[keyof T]来过滤掉属性(第一步中已经修改了)
type Type7<T> = {
[P in keyof T] : T[P] extends Function ? T[P] : undefined
}[keyof T]
interface type8 {
a: number
b():void
}
let abc: Type7<type8>
// infer 条件类型推断
// 传入四个类型 如果类型是一个数组,那么返回数组的某一项的类型 number 索引访问
type Type8<T> = T extends any[] ? T[number] : T
let T1: Type8<string[]> // string
let T2: Type8<number> // number
// infer 的写法
type Type9<T> = T extends Array<infer U> ? U : T // infer 指向的是构成这个数组的数据类型
let T3: Type9<Array<{ a: 1, b: 2 }>> // {a:1,b:2} 其他测试用例如上
let T4 : Exclude<'a' | 'b' | 'c','a' | 'b'> // 剩下'c', 排除相同的
let T5: Extract<'a' | 'b' | 'c', 'a' | 'b'> // 剩下 'a' 'b' 选取相同的
let T6: NonNullable<null | undefined | number | string> // number | string 去除 null undefined
let T7: ReturnType<() => number> // 根据传入的函数返回函数的返回值作为类型
class Aclass {
}
let T8: InstanceType<typeof Aclass> //
let T9: Aclass
interface type 都支持嵌套写法
// interface 写法
interface Ip {
name: string;
child?: Ip;
}
let child: Ip = {
name: "str",
child: {
name: "test"
}
};
// type 写法
type Ip = {
name: string;
child?: Ip;
};
let child: Ip = {
name: "child",
child: {
name: "haha"
}
};
// 有趣的写法
type LinkedList<T> = T & { next: LinkedList<T> }; // people = {name:'',next:{name:'',next:{...}}}
interface Person {
name: string;
}
var people: LinkedList<Person>;
var s = people.name;
var s = people.next.name;
var s = people.next.next.name;
var s = people.next.next.next.name;
// never 配合 switch的使用
// 可以检测当前的判断条件是否使用完,并且传入未知类型的时候抛错
function assertNever(err: never): never {
throw new Error('type error' + err)
}
type circle = {
type: 'circle'
radius: number
}
type rance = {
type: 'rance'
width: number,
height: number
}
type area = circle | rance
function computeAreaArea(area: area) {
switch (area.type) {
case 'circle' :
return area.radius ** 2 * Math.PI
case 'rance':
return area.height * area.width
default :
return assertNever(area)
}
}
// keyof 只会返回不为 null undefined never 的类型
interface EnumType {
a: never,
b: undefined,
c: null,
d: number,
e:object
}
type TypeEnumType = keyof EnumType // a | b | c | d | e
type TypeEnumType1 = EnumType[keyof EnumType] // number | object 去除了了3种假类型
type ReadonlyType<T> = {
readonly [P in keyof T] ? : T[P]
}
let readOnly: ReadonlyType<EnumType> = {} // 将 EnumType 所有类型都变为了了 只读
interface I {
name: "ccc";
}
interface P {
age: "bbb";
}
var a: I & P = {
name: "ccc",
age: "bbb"
};
// 获取对象的属性
function pluck<T, K extends keyof T>(o: T, names: K): T[K] {
return o[names];
}
// 升级版
function pluck1<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map(item => o[item]);
}
// keyof用法
interface Personal {
name: string;
age: number;
}
//keyof Personal ==> 'name' | 'age' 这种的联合类型 可以使用in来循环
let ppp: keyof Personal = "name";
let ppp1: keyof Personal = "age";
let ppp2: keyof Personal = "ss"; // error 值只能为 name | age
- keyof 用法二
keyof 和 T[K]与字符串索引签名进行交互。 如果你有一个带有字符串索引签名的类型,那么 keyof T 会是 string。 并且 T[string]为索引签名的类型
interface Map1<T> {
[key: number]: T;
}
let pp: keyof Map1<string>; // pp 类型为number
let pp4: Map1<string>[0]; // 返回的类型是string
interface Map2<T> {
[key: string]: T;
}
let pp1: keyof Map1<string>; // pp1 类型为string
let pp3: Map2<number>["foo"]; // 返回的类型是number
// 通过这个类型生成一个只读版本 in 内部使用了for---in循环
interface PersonPartial {
name?: string;
age?: number;
}
// 使用
type ReadonlyPersonPartial<T> = {
readonly [key in keyof PersonPartial]: PersonPartial[key]
}
let b: ReadonlyPersonPartial<string> = {
name: 'string',
age: 123
}
type Map2<T> = {
[key in keyof PersonPartial]?: T;
}
var a: Map2<string> = {
name: '123',
}
// 封装一些通用的版本
type BeNull<T> = {
[P in keyof T]:T[P] | null
}
type BeEmpty<T> = {
[P in keyof T]?:T[P]
}
interface a {
name: string;
age: number;
}
// T 相当于上面有 name | age
// [key in T] 循环 name age ,每一个key就是name age 那么 a[name],a[age] j
type b<T extends keyof a> = { [key in T]: a[key] };
let c: b<"name" | "age"> = {
name: "123",
age: 12
};
- 内置的 pick record exclude的理解 慢慢来吧
// pick 的作用是传入一个接口,返回接口里面特定的字段类型
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
interface b {
name: string,
age:number
}
let cc: Pick<b, 'name' | 'age'> = {
name: 'cc',
age:123
}
// 传入属性,生成一个接口 生成一个 name age 都是string的interface
type Record<K extends keyof any, T> = {
[P in K]: T;
};
let mmm: Record<'name' | 'age', string> = {
name: 'ccc',
age:'20'
}
// 排除相同的 extends 可以理解为 T 可以赋值给 U 可以赋值返回never 否则 返回 T
type Exclude<T, U> = T extends U ? never : T;
interface a {
name:string
}
interface b {
name: string,
age:number
}
interface c {
name: string,
age: number,
hobby:any
}
// 这两个东西表示出来了 是分开来搞的 首先 a extends b => a b extends b=>never 所以返回的是 a
let nnn: Exclude<a | b, b> // 返回 a
let nnnn: Exclude<a | b, a> // 返回 never a extends a => never b extends a b可以赋值给a 返回never
let ccc: Exclude<a | b | c, c>
let b: a extends b ? number : string // a 不能赋值给 b 所以返回了string b的类型就是string
let nnn:Exclude<keyof b,keyof a> // 排除相同的过后 剩下的就是 ‘age’ 'name'|'age' extends 'name' 难道是 name extends name , age extends name 分开来的 先这样理解吧
type mm = 'number' | 'age';
type nn = 'age'
let c: mm extends nn ? never : mm; // mm 不能赋值给 nn 所以返回值是 mm 并不是上面Exclude 返回的 age 这个可以理解为传入泛型变量的时候ts 帮我们去循环 extends(赋值了一下)
// 取出相同的
type Extract<T, U> = T extends U ? T : never; // T 可以赋值给 U的话 表示的是T中的字段 U中肯定都存在 返回了 U。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。